package com.zhihuishu.micro.course.service.impl;

import com.zhihuishu.micro.course.dto.TreenityDto;
import com.zhihuishu.micro.course.service.TreenityBatchDBService;
import com.zhihuishu.micro.course.service.TreenityBatchRedisService;
import com.zhihuishu.micro.course.service.TreenityBatchService;
import com.zhihuishu.micro.course.service.TreenityService;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @author Jiangli
 * @date 2016/10/20 9:33
 *
 * @see TreenityService
 */
public abstract class BaseTreenityBatchServiceImpl<DTO extends TreenityDto> extends  BaseTreenityServiceImpl<DTO> implements TreenityBatchService<DTO> {
    protected abstract TreenityBatchDBService<DTO,?> getDBService();
    protected abstract TreenityBatchRedisService<DTO> getRedisService();

    @Override
    public void sort(List<DTO> dbDtoList, long updateUserId) {

        getDBService().sort(dbDtoList, updateUserId);

        getRedisService().sort(dbDtoList,updateUserId);

        log.warn("执行排序 size:[{}]，更新人[{}]!" , dbDtoList.size(),updateUserId) ;
    }

    @Override
    public void updateMulti(List<DTO> dtos, long updateUserId) {
        Assert.notNull(dtos);
        if (dtos.size() == 0) {
            return;
        }

        //若更新了oneToManyId 需要维护新老关系
        List<Integer> oTMChangedIdList = new ArrayList<Integer>(dtos.size());
        List<DTO> dtoNewList = new ArrayList<DTO>(dtos.size());
        for (DTO dto : dtos) {
            Assert.notNull(dto.getId());

            if(dto.getOneToManyId() != null){
                oTMChangedIdList.add(dto.getId());
                dtoNewList.add(dto);
            }
        }
        //-删除老关系
        if (oTMChangedIdList.size() > 0) {
            List<DTO> dtoOldList = list(oTMChangedIdList);
            getRedisService().deleteRelationShip(dtoOldList);
        }


        // 更新数据库中的章
        getDBService().updateMulti(dtos,updateUserId);

        List<Integer> idList = new ArrayList<Integer>(dtos.size());

        for (DTO dto : dtos) {
            idList.add(dto.getId());
        }

        //直接查库，然后更新缓存
        List<DTO> list = getDBService().list(idList);
        log.debug("updateMulti {} from params:[{}]!" ,getDTOName(),String.valueOf(dtos)) ;
        log.debug("updateMulti {} from db:[{}]!" ,getDTOName(),String.valueOf(list) ) ;

        getRedisService().updateMulti(list,updateUserId);

        log.warn("执行更新Multi dto:[{}]，更新人[{}]!" , dtos,updateUserId) ;

        //-添加新关系
        if (oTMChangedIdList.size() > 0) {
            getRedisService().addRelationShip(dtoNewList);
        }
    }

    public void deleteMulti(List<Integer> dtoIds, long deleteUserId) {
        Assert.notNull(dtoIds, "dtoIds不能为空");
        if (CollectionUtils.isEmpty(dtoIds)) {
            return;
        }

        //remove from db
        getDBService().deleteMulti(dtoIds,deleteUserId);

        List<DTO> list = list(dtoIds);

        //remove relationship from redis
        getRedisService().deleteRelationShip(list);

        //remove object hash from redis
        getRedisService().deleteMulti(dtoIds,deleteUserId);
    }

    @Override
    public void deleteMultiByMultiOneToManyKey(List<Long> oneToManyKeys, long deleteUserId) {
        if (!CollectionUtils.isEmpty(oneToManyKeys)) {

            List<Integer> dtoIdList = listDtoIdsByMultiOneToManyKey(oneToManyKeys);

            deleteMulti(dtoIdList,deleteUserId);
        }
    }

    @Override
    public List<DTO> listByMultiOneToManyKey(List<Long> oneToManyIds) {
        List<Integer> dtoIdList = listDtoIdsByMultiOneToManyKey(oneToManyIds);

        final List<DTO> dto = list(dtoIdList);

        return dto.isEmpty() ? null : dto ;
    }

    @Override
    public List<Integer> listDtoIdsByMultiOneToManyKey(List<Long> oneToManyIds) {
        List<Integer> ret = new LinkedList<Integer>();
        for (Long oneToManyId : oneToManyIds) {
            List<Integer> list = listDtoIds(oneToManyId);
            ret.addAll(list);
        }
        return ret;
    }
}
